﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using Base32;
using OSS.NBEncode.Entities;
using OSS.NBEncode.Extensions;
using OSS.NBEncode.Transforms;
using Synology.DS.Common;
using Synology.DS.Interface.Abstract;
using Synology.DS.Interface.Exception;

namespace Synology.DS.Core
{
	public class TorrentFileTransfomer : ITorrentFileTransfomer
	{
		public string Transform2Magnet(string filePath)
		{
			if (!File.Exists(filePath))
				throw new FileNotFoundException("", filePath);

			string result;
			Log.Info("Transforming torrent file: '{0}'...", filePath);
			using (FileStream FS = new FileStream(filePath, FileMode.Open, FileAccess.Read))
			using (SHA1 sha1 = new SHA1Managed())
			{
				BObjectTransform transformer = new BObjectTransform();
				BDictionary torrentDictionary = transformer.DecodeNext(FS) as BDictionary;

				if (torrentDictionary == null)
					throw new TorrentFileTransformException("Cannot load torrent file dictionary");

				BDictionary infoSection = torrentDictionary.FindSection("info") as BDictionary;

				if (infoSection == null)
					throw new TorrentFileTransformException("Cannot load info section");

				Encoding encoding = GetEncoding(torrentDictionary);
				BByteString nameSection = infoSection.FindSection("name") as BByteString;

				if (nameSection == null)
					throw new TorrentFileTransformException("Cannot load name section");

				byte[] infoData = infoSection.ToByteArray();
				string hashString = Base32Encoder.Encode(sha1.ComputeHash(infoData));

				result = string.Format("magnet:?xt=urn:btih:{0}&db={1}", hashString, HttpUtility.UrlEncode(nameSection.ConvertToText(encoding)));
			}
			
			Log.Info("Transformed. URL: '{0}'", result);

			return result;
		}

		private Encoding GetEncoding(BDictionary torrent)
		{
			BByteString encoding = torrent.FindSection("encoding") as BByteString;
			return encoding == null ? Encoding.ASCII : Encoding.GetEncoding(encoding.ConvertToText(Encoding.ASCII));
		}
	}
}
